/*
 * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2009.
 *
 * Licensed under the Aduna BSD-style license.
 */

package edu.tju.commons.collections.iterators;

import java.util.Iterator;
import java.util.NoSuchElementException;

import edu.tju.commons.concurrent.locks.Lock;

/**
 * An iterator that holds on to a lock until the iterator is closed. Upon
 * closing, the underlying iterator is closed before the lock is released.
 */
public class LockingIterator<E> extends IteratorWrapper<E> {

	/**
	 * The lock to release when the iterator is closed.
	 */
	private final Lock lock;

	/**
	 * Creates a new LockingIterator.
	 * 
	 * @param lock
	 *        The lock to release when the itererator is closed, must not be
	 *        <tt>null</tt>.
	 * @param iter
	 *        The underlying iterator, must not be <tt>null</tt>.
	 */
	public LockingIterator(Lock lock, Iterator<? extends E> iter) {
		super(iter);

		assert lock != null;
		this.lock = lock;
	}

	@Override
	public synchronized boolean hasNext() {
		if (isClosed()) {
			return false;
		}

		if (super.hasNext()) {
			return true;
		}

		close();
		return false;
	}

	@Override
	public synchronized E next() {
		if (isClosed()) {
			throw new NoSuchElementException("Iterator has been closed");
		}

		return super.next();
	}

	@Override
	public synchronized void remove() {
		if (isClosed()) {
			throw new IllegalStateException();
		}

		super.remove();
	}

	@Override
	protected void handleClose() {
		try {
			super.handleClose();
		}
		finally {
			synchronized (this) {
				lock.release();
			}
		}
	}
}
